package com.cwt_taxi_xa.protocol.socket;

import android.text.TextUtils;
import android.util.Log;

import com.cwt_taxi_xa.data.SocketConfig;

import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;


/**
 * @author zr
 * socket连接通讯平台
 * modify by undi
 */
public class DispatchCenterClient{

	private static final String TAG = "DispatchCenterClient-ud";
	private final boolean debug = true;
	private boolean hasConnected = false;
	private boolean networkIsAvailable = false;
	//client引导
	private  ClientBootstrap bootstrap = null;
	//通道状态
	private  ChannelFuture channelFuture = null;
	//消息通道
	private  Channel channel = null;

	private SocketConfig mSocketConfig;

	private long mSleepTime = 3*60*1000;
	private Thread mThread;
	/**
	 * 消息解码后
	 */
	MessageAssembly.MessageCallback messageCallback;

	public DispatchCenterClient() {
	}

	public DispatchCenterClient(MessageAssembly.MessageCallback messageCallback) {
		this.messageCallback = messageCallback;
		createBootStrap();
	}

	public void setSocketConfig(SocketConfig mSocketConfig) {
		Log.d(TAG,"setSocketConfig");
		if(this.mSocketConfig == null && mSocketConfig != null){
			this.mSocketConfig = mSocketConfig;
			printD("mSocketConfig init connect");
			printE("setSocketConfig mSocketConfig:" + mSocketConfig + "0");
			bootstrapConnect(mSocketConfig);
		}else if(this.mSocketConfig != null && mSocketConfig != null){
			printE("setSocketConfig mSocketConfig:" + this.mSocketConfig + "1" );
			printE("setSocketConfig mSocketConfig:" + mSocketConfig + "2" );
			if(!this.mSocketConfig.equals(mSocketConfig)){
				printD("mSocketConfig change connect");
				bootstrapConnect(mSocketConfig);
			}else{
				printE("mSocketConfig equals");
			}
		}else if(this.mSocketConfig == null && mSocketConfig == null){
			printE("mSocketConfig fail");
		}

	}

	/**
	 * netty通道
	 */
	IChannelHandlerListener channelHandlerListener = new IChannelHandlerListener() {
		@Override
		public void channelDisconnected(ChannelHandlerContext ctx) {
			printD("channelDisconnected");
			hasConnected = false;
			startThread();
		}

		@Override
		public void channelConnected(ChannelHandlerContext ctx) {
			printD("channelConnected");
			hasConnected = true;
			stopThread();
		}

		@Override
		public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
			printD("messageReceived");
			channel = ctx.getChannel();
			if ((e.getMessage() instanceof ChannelBuffer)) {
				ChannelBuffer channelBuffer = (ChannelBuffer) e.getMessage();
				byte[] bytes = channelBuffer.array();
				messageCallback.callback(bytes);
			}
		}

		@Override
		public void exceptionCaught(ChannelHandlerContext ctx) {
			printD("exceptionCaught");
		}
	};

	/**
	 * 初始化连接
	 */
	public synchronized void createBootStrap() {
		bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(
				Executors.newCachedThreadPool(),
				Executors.newCachedThreadPool()));
		bootstrap.setOption("receiveBufferSizePredictorFactory", new FixedReceiveBufferSizePredictorFactory(655350));
		DispatchCenterClientPipelineFactory ccpf = new DispatchCenterClientPipelineFactory(channelHandlerListener);
		bootstrap.setPipelineFactory(ccpf);

		bootstrap.setOption("tcpNoDelay", true);
		bootstrap.setOption("keepAlive", true);
		bootstrap.setOption("reuseAddress", true);
	}

	public synchronized void bootstrapConnect(SocketConfig mSocketConfig){
		try {
			if(mSocketConfig != null && networkIsAvailable && !hasConnected && mSocketConfig.isOpen()){

				/**向目标地址发起一个连接*/
				bootstrapConnect(mSocketConfig.getIp(),mSocketConfig.getPort());
			}else{
				bootstrapDisConnect();
				//printE("mSocketConfig networkIsAvailable:" + networkIsAvailable + " hasConnected:" + hasConnected + " isOpen:" + mSocketConfig.isOpen());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	//连接服务器
	private synchronized void bootstrapConnect(final String ip, final String port){
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					if(bootstrap != null && !TextUtils.isEmpty(ip) && !TextUtils.isEmpty(port)){
						printD("bootstrapConnect ip:" + ip + " port:" + port);
						startThread();
						/**向目标地址发起一个连接*/
						channelFuture = bootstrap.connect(new InetSocketAddress(ip, Integer.parseInt(port)));
						channel = channelFuture.getChannel();
						// 等待链接成功，成功后发起的connected事件将会使handler开始发送信息并且等待messageRecive
						channelFuture.awaitUninterruptibly();
					}else{
						printE("bootstrapConnect ip" + ip + " port:" + port);
					}
				} catch (Exception e) {
					e.printStackTrace();

				}
			}
		}).start();
	}

	/**
	 * 断开服务器
	 */
	public synchronized void bootstrapDisConnect(){
		hasConnected = false;
		printE("bootstrapDisConnect");
		try {
			if(bootstrap != null){
				if(channel != null){
					channel.close();
				}
				if(channelFuture != null){
					channelFuture.cancel();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		stopThread();
	}

	public boolean isConnect(){
		if(channelFuture==null || channel == null){
			return false;
		}
		if(!channel.isConnected()){
			return false;
		}
		if(!channelFuture.isSuccess()){
			return false;
		}
		return true;
	}

	public boolean writeMsg(byte[] buffer){
		if(isConnect()){
			// 获得此对象的长度
			ChannelBuffer channelBuffer = ChannelBuffers.buffer(buffer.length);
			// 将 获得到的数组写入 channelBuffer中
			channelBuffer.writeBytes(buffer);
			ChannelFuture lastWriteFuture = channel.write(channelBuffer);
			if (lastWriteFuture != null) {
				// 等待或监听数据
				lastWriteFuture.awaitUninterruptibly();
			}
			return true;
		}else{
			printE("writeMsg fail");
		}
		return false;
	}

	public void setConnect(boolean connected) {
		this.networkIsAvailable = connected;
		if(connected){
			bootstrapConnect(mSocketConfig);
		}else{
			bootstrapDisConnect();
		}
	}

	private void printD(String message){
		if(debug){
			Log.d(TAG,message);
		}
	}
	private void printE(String message){
		if(debug){
			Log.e(TAG,message);
		}
	}

	private boolean conditionBreak(){
		if(mSocketConfig != null && networkIsAvailable && !hasConnected && mSocketConfig.isOpen()){
			return false;
		}
		return true;
	}


	private synchronized void startThread(){
		if(mThread == null || mThread.isInterrupted()){
			mThread = new Thread(new Runnable() {
				@Override
				public void run() {
					while (!Thread.currentThread().isInterrupted()){
						printE("Thread while");
						try {
							if(conditionBreak()){
								printE("Thread connect break before");
								break;
							}
							Thread.sleep(mSleepTime);
							if(!conditionBreak()){
								bootstrapConnect(mSocketConfig);
							}else{
								printE("Thread connect break after");
								break;
							}
						} catch (InterruptedException e) {
							//e.printStackTrace();
							printE("Thread connect break " + e.getMessage());
							break;
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
					printD("Thread running end");
				}
			});
			printD("Thread start");
			mThread.start();
		}
	}

	private synchronized void stopThread(){
		printD("Thread stop");
		if(mThread != null){
			mThread.interrupt();
			mThread = null;
		}
	}

}
